package com.library.management.repository;

import com.library.management.entity.Book;
import com.library.management.entity.Reservation;
import com.library.management.entity.User;
import com.library.management.enums.ReservationStatus;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 预约记录数据访问层接口
 * 提供预约记录相关的数据库操作
 *
 * @author 开发者
 * @version 1.0
 * @since 2025-10-20
 */
@Repository
public interface ReservationRepository extends JpaRepository<Reservation, Long> {

    // ========== 用户相关查询 ==========

    /**
     * 根据用户查找预约记录
     *
     * @param user     用户
     * @param pageable
     * @return 预约记录列表
     */
    List<Reservation> findByUser(User user, Pageable pageable);

    /**
     * 根据用户ID查找预约记录
     *
     * @param userId 用户ID
     * @return 预约记录列表
     */
    List<Reservation> findByUserId(Long userId);

    /**
     * 根据用户和状态查找预约记录
     *
     * @param user 用户
     * @param status 预约状态
     * @return 预约记录列表
     */
    List<Reservation> findByUserAndStatus(User user, ReservationStatus status);

    // ========== 图书相关查询 ==========

    /**
     * 根据图书查找预约记录
     *
     * @param book 图书
     * @return 预约记录列表
     */
    List<Reservation> findByBook(Book book);

    /**
     * 根据图书ID查找预约记录
     *
     * @param bookId 图书ID
     * @return 预约记录列表
     */
    List<Reservation> findByBookId(Long bookId);

    /**
     * 根据图书和状态查找预约记录
     *
     * @param book 图书
     * @param status 预约状态
     * @return 预约记录列表
     */
    List<Reservation> findByBookAndStatus(Book book, ReservationStatus status);

    // ========== 状态相关查询 ==========

    /**
     * 根据预约状态查找记录
     *
     * @param status 预约状态
     * @return 预约记录列表
     */
    List<Reservation> findByStatus(ReservationStatus status);

    /**
     * 查找有效的预约记录（状态为等待中且未过期）
     *
     * @param currentTime 当前时间
     * @return 有效预约记录列表
     */
    @Query("SELECT r FROM Reservation r WHERE r.status = 'PENDING' AND r.expireDate > :currentTime")
    List<Reservation> findValidReservations(@Param("currentTime") LocalDateTime currentTime);

    // ========== 时间相关查询 ==========

    /**
     * 查找预约日期在指定范围内的记录
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 预约记录列表
     */
    List<Reservation> findByReserveDateBetween(LocalDateTime startDate, LocalDateTime endDate);

    /**
     * 查找过期日期在指定范围内的记录
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 预约记录列表
     */
    List<Reservation> findByExpireDateBetween(LocalDateTime startDate, LocalDateTime endDate);

    /**
     * 查找已过期的预约记录
     *
     * @param currentTime 当前时间
     * @return 过期预约记录列表
     */
    @Query("SELECT r FROM Reservation r WHERE r.status = 'PENDING' AND r.expireDate <= :currentTime")
    List<Reservation> findExpiredReservations(@Param("currentTime") LocalDateTime currentTime);

    // ========== 复杂查询方法 ==========

    /**
     * 检查用户是否已经预约了某本图书且预约有效
     *
     * @param userId 用户ID
     * @param bookId 图书ID
     * @param currentTime 当前时间
     * @return true-已预约，false-未预约
     */
    @Query("SELECT COUNT(r) > 0 FROM Reservation r WHERE r.user.id = :userId AND r.book.id = :bookId AND r.status = 'PENDING' AND r.expireDate > :currentTime")
    boolean existsActiveReservationByUserAndBook(@Param("userId") Long userId,
                                                 @Param("bookId") Long bookId,
                                                 @Param("currentTime") LocalDateTime currentTime);

    /**
     * 查找图书的预约队列（按优先级和预约时间排序）
     *
     * @param bookId 图书ID
     * @return 预约队列
     */
    @Query("SELECT r FROM Reservation r WHERE r.book.id = :bookId AND r.status = 'PENDING' ORDER BY r.priority ASC, r.reserveDate ASC")
    List<Reservation> findReservationQueueByBookId(@Param("bookId") Long bookId);

    /**
     * 统计用户的预约数量
     *
     * @param userId 用户ID
     * @return 预约数量
     */
    long countByUserId(Long userId);

    /**
     * 统计图书的预约数量
     *
     * @param bookId 图书ID
     * @return 预约数量
     */
    long countByBookId(Long bookId);

    /**
     * 查找需要发送通知的预约记录（图书可用但未发送通知）
     *
     * @return 需要通知的预约记录
     */
    @Query("SELECT r FROM Reservation r WHERE r.status = 'AVAILABLE' AND r.notifySent = false")
    List<Reservation> findReservationsNeedNotification();

    /**
     * 查找即将过期的预约记录（在指定天数内过期）
     *
     * @param currentTime 当前时间
     * @param expireTime 过期时间阈值
     * @return 即将过期预约记录
     */
    @Query("SELECT r FROM Reservation r WHERE r.status = 'PENDING' AND r.expireDate BETWEEN :currentTime AND :expireTime")
    List<Reservation> findReservationsExpiringSoon(@Param("currentTime") LocalDateTime currentTime,
                                                   @Param("expireTime") LocalDateTime expireTime);

    /**
     * 查找指定天数内创建的预约记录
     *
     * @param startTime 开始时间
     * @return 预约记录列表
     */
    @Query("SELECT r FROM Reservation r WHERE r.reserveDate >= :startTime")
    List<Reservation> findReservationsCreatedInLastDays(@Param("startTime") LocalDateTime startTime);

    /**
     * 根据用户和图书查找预约记录
     *
     * @param userId 用户ID
     * @param bookId 图书ID
     * @return 预约记录
     */
    @Query("SELECT r FROM Reservation r WHERE r.user.id = :userId AND r.book.id = :bookId")
    Optional<Reservation> findByUserIdAndBookId(@Param("userId") Long userId,
                                                @Param("bookId") Long bookId);

    /**
     * 统计每日预约数量
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 预约统计
     */
    @Query("SELECT DATE(r.reserveDate), COUNT(r) FROM Reservation r WHERE r.reserveDate BETWEEN :startDate AND :endDate GROUP BY DATE(r.reserveDate) ORDER BY DATE(r.reserveDate) DESC")
    List<Object[]> countReservationsByDay(@Param("startDate") LocalDateTime startDate,
                                          @Param("endDate") LocalDateTime endDate);
}